package person.wangchen11.editor.edittext;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.support.v4.widget.EdgeEffectCompat;
import android.text.ClipboardManager;
import android.text.Editable;
import android.text.Selection;
import android.text.TextPaint;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;

@SuppressWarnings("deprecation")
public class MyEditText extends View implements OnGestureListener,TextWatcher {
	protected static final String TAG="MyEditText";
	private GestureDetector mGestureDetector;
	private Scroller mScroller;
	private EdgeEffectCompat mEdgeEffectTop;
	private EdgeEffectCompat mEdgeEffectBottom;
	//private EdgeEffectCompat mEdgeEffectLeft;
	//private int mCursor=0;
	private MyInputConnection mBaseInputConnection;
	MyLayout mLayout;
	Paint mCursorPaint=new Paint();
	Paint mSelectionPaint=new Paint();
	TextPaint mTextPaint=new TextPaint();
	TextPaint mLineNumberPaint=new TextPaint();
	public MyEditText(Context context) {
		super(context);
		init();
	}
	

	public MyEditText(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	
	public void setText(CharSequence charSequence){
		if(mBaseInputConnection==null)
			mBaseInputConnection=new MyInputConnection(this)
		{
		    public boolean clearMetaKeyStates(int states) {
		    	mDownState=0;
		    	return super.clearMetaKeyStates(states);
		    }
		    
			@Override
		    public boolean performContextMenuAction(int id) {
				MyEditText.this.performContextMenuAction(id);
		        return super.performContextMenuAction(id);
		    }
			
			@Override
			public boolean setSelection(int start, int end) {
				
				if(start==end){
					post(new Runnable() {
						@Override
						public void run() {
							bringPosToVisible(getCursor());
							postInvalidate();
						}
					});
				}
				
				if(isMoveSelectionStart()){
					postDelayed(new Runnable() {
						@Override
						public void run() {
							bringPosToVisible(getSelectionStart());
							postInvalidate();
						}
					},100);
				}else
				if(isMoveSelectionEnd()){
					postDelayed(new Runnable() {
						@Override
						public void run() {
							bringPosToVisible(getSelectionEnd());
							postInvalidate();
						}
					},100);
				}
				return super.setSelection(start, end);
			}
		};
		
		mBaseInputConnection.getEditable().clear();
		if(charSequence!=null){
			mBaseInputConnection.getEditable().insert(0, charSequence);
		}
		else{
		}

		if(getCursor()>mBaseInputConnection.getEditable().length())
			setCursor(mBaseInputConnection.getEditable().length());
		makeLayout();
	}

	public Editable getText(){
		return mBaseInputConnection.getEditable();
	}
	
	private void init()
	{
		mGestureDetector=new GestureDetector(getContext(), this);
		StringBuilder builder=new StringBuilder();
		builder.append("#include <stdio.h>\n");
		builder.append("int main( void )\n");
		builder.append("{\n");
		builder.append("int a=0x7f;\n");
		builder.append("int b=0x00;\n");
		builder.append("/*\n");
		builder.append("*多行注释 ！！\n");
		builder.append("*/\n");
		builder.append("\tprintf(\"输出:%d.\\n\",a*b);\n");
		builder.append("//单行注释\n");
		builder.append("\treturn 0;\n");
		builder.append("}");
		/*
		for(int i=0;i<5000;i++){
			builder.append("int main{ return 0; }\r\n");
		}
		*/
		String str=builder.toString();
		for(int i=0;i<1;i++)
			builder.append(str);
		float size=getContext().getResources().getDisplayMetrics().density*16f;
		mTextPaint.setTextSize(size);
		mTextPaint.setTypeface(Typeface.MONOSPACE);
		mScroller=new Scroller(getContext());
		mEdgeEffectTop=new EdgeEffectCompat(getContext());
		mEdgeEffectTop.setSize(getWidth(), getHeight());
		mEdgeEffectBottom=new EdgeEffectCompat(getContext());
		mEdgeEffectBottom.setSize(getWidth(), getHeight());
		//mEdgeEffectLeft=new EdgeEffectCompat(getContext());
		//mEdgeEffectLeft.setSize(getHeight(),getWidth());
		mLineNumberPaint=new TextPaint(mTextPaint);
		mLineNumberPaint.setColor(Color.GRAY);
		mSelectionPaint.setColor(Color.argb(0x60, 0x80, 0xf8, 0x80));
		mLineNumberPaint.setTypeface(Typeface.MONOSPACE);
		float strokeWidth=getContext().getResources().getDisplayMetrics().density;
		if(strokeWidth<1)
			strokeWidth=1;
		mCursorPaint.setStrokeWidth(strokeWidth);
		setScrollContainer(true);
		setText(builder.toString());
		this.post(new Runnable(){
			int colors[]={
					Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,
					Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,
					Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,
					Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),
					Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),
					Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),
					Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),
					Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),
					Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),Color.argb(0x80, 0xF0, 0x80, 0x80),
					};
			int num=0;
			@Override
			public void run() {
				if(num>=colors.length)
					num=0;
				mCursorPaint.setColor(colors[num]);
				MyEditText.this.postDelayed(this, 20);
				MyEditText.this.postInvalidate();
				num++;
			}
		});
		setScrollbarFadingEnabled(true);
	}
	
	@Override
	public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
		return mBaseInputConnection;
	}
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		post(new Runnable() {
			@Override
			public void run() {
				setCursor(getCursor());
				bringPosToVisible(getCursor());
			}
		});
		mEdgeEffectTop.setSize(getWidth(), getHeight());
		mEdgeEffectBottom.setSize(getWidth(), getHeight());
		//mEdgeEffectLeft.setSize(getHeight(),getWidth());
		super.onSizeChanged(w, h, oldw, oldh);
	}
	
	@SuppressLint("ClickableViewAccessibility")
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(event.getAction()==MotionEvent.ACTION_DOWN)
		{
			mScroller.abortAnimation();
		}
		mGestureDetector.onTouchEvent(event);
		return true;
	}

	private Rect mBoundsOfCursor=new Rect();
	@Override
	protected void onDraw(Canvas canvas) {
		
		if(mLayout!=null)
		{
			//计算选择条
			int selectLineStart=0;
			int selectLineEnd=0;
			float selectStartX=0;
			float selectEndX=0;
			if(isSelection())
			{
				int start=getSelectionStart();
				int end=getSelectionEnd();
				selectLineStart=mLayout.getLineForOffset(start);
				selectLineEnd=mLayout.getLineForOffset(end);
				selectStartX=mLayout.getPrimaryHorizontal(start);
				selectEndX=mLayout.getPrimaryHorizontal(end);
			}
			
			int cursor=getCursor();
			float x=mLayout.getPrimaryHorizontal(cursor);
			int line=mLayout.getLineForOffset(cursor);
			mLayout.getLineBounds(line, mBoundsOfCursor); 
			canvas.drawLine(x, mBoundsOfCursor.top, x, mBoundsOfCursor.bottom, mCursorPaint);
			
			if(isSelection()){
				int r=mBoundsOfCursor.height()/2;
				canvas.drawCircle(x, mBoundsOfCursor.bottom + r, r, mSelectionPaint);
				
				cursor=getSelectionStart();
				x=mLayout.getPrimaryHorizontal(cursor);
				line=mLayout.getLineForOffset(cursor);
				mLayout.getLineBounds(line, mBoundsOfCursor); 
				canvas.drawLine(x, mBoundsOfCursor.top, x, mBoundsOfCursor.bottom, mCursorPaint);

				canvas.drawCircle(x, mBoundsOfCursor.bottom + r, r, mSelectionPaint);
			}
			//////////////////////////////////////////
			canvas.getClipBounds(mBoundsOfCursor);
			int lineStart=mLayout.getLineForVertical(mBoundsOfCursor.top);
			int lineEnd=mLayout.getLineForVertical(mBoundsOfCursor.bottom);
			float descent=mLayout.getPaint().getFontMetrics().descent;
			for(int i=lineStart;i<=lineEnd;i++){
				mLayout.getLineBounds(i, mBoundsOfCursor);
				String value=String.valueOf(i);
				canvas.drawText(value, mBoundsOfCursor.left-mLineNumberPaint.measureText(value)-32f, mBoundsOfCursor.bottom - descent , mLineNumberPaint);
				
				if(isSelection())
				{//画选择框 
					if(i>selectLineStart && i<selectLineEnd){
						canvas.drawRect(mBoundsOfCursor, mSelectionPaint);
					}
					else
					if(i==selectLineStart )
					{
						if(i==selectLineEnd){
							canvas.drawRect(selectStartX, mBoundsOfCursor.top, selectEndX, mBoundsOfCursor.bottom, mSelectionPaint);
						}
						else{
							canvas.drawRect(selectStartX, mBoundsOfCursor.top, mBoundsOfCursor.right, mBoundsOfCursor.bottom, mSelectionPaint);
						}
					}
					else
					if(i==selectLineEnd )
					{
						canvas.drawRect(0, mBoundsOfCursor.top, selectEndX, mBoundsOfCursor.bottom, mSelectionPaint);
					}
				}
				//mLineNumberPaint
			}

			mLayout.draw(canvas);
		}
		canvas.save();
		canvas.translate(getScrollX(), getScrollY());
		mEdgeEffectTop.draw(canvas);
		canvas.restore();
		canvas.save();
		canvas.rotate(180);
		canvas.translate( -(getScrollX()+getWidth()), -(getScrollY()+getHeight()) );
		mEdgeEffectBottom.draw(canvas);
		canvas.restore();
		canvas.rotate(-90);
		canvas.translate( -(getScrollY()+getHeight()) ,getScrollX() );
		//mEdgeEffectLeft.draw(canvas);
		canvas.save();
	}
	
	private void makeLayout(){
		if(getText()!=null)
		{
			mLayout=mBaseInputConnection.getLayout();
			//mLayout=new StaticLayout(mEditable, mTextPaint, Integer.MAX_VALUE,Layout.Alignment.ALIGN_NORMAL,1f,0f,false);
			//mLayout=new DynamicLayout(getText(),mTextPaint,Integer.MAX_VALUE,Layout.Alignment.ALIGN_NORMAL,1f,0f,false);
		}
		Log.i(VIEW_LOG_TAG, "mLayout:"+mLayout);
	}

	public TextPaint getPaint(){
		return mTextPaint;
	}
	
	private float getWidthOfBit(int bit)
	{
		String str="";
		for(int i=0;i<bit;i++)
		{
			str+='0';
		}
		return getPaint().measureText(str);
	}

	public int getBoundOfLeft(){
		int left=(int) getWidthOfBit(getBitOfNum(getLineCount()));
		return -(left+32);
	}

	public int getBoundOfRight(){
		if(mLayout==null)
			return getWidth();
		return Integer.MAX_VALUE;
	}
	
	public int getBoundOfTop(){
		return 0;//(int) -mTextPaint.getTextSize();
	}
	
	public int getBoundOfBottom(){
		if(mLayout==null)
			return getHeight();
		int h1=mLayout.getHeight();
		int h2=getHeight();
		return h1>h2?h1:h2;
	}
	
	@Override
	public boolean canScrollHorizontally(int direction) {
		int newX=getScrollX()+direction;
		if( newX >= getBoundOfLeft()  && newX<=getBoundOfRight()  )
			return true;
		return false;
	}
	
	@Override
	public boolean canScrollVertically(int direction) {
		int newY=getScrollY()+direction;
		if( newY >=getBoundOfTop() && newY <= getBoundOfBottom() )
			return true;
		return false;
	}
	
	@Override
	public void scrollTo(int x, int y) {
		int left=getBoundOfLeft();
		int right=getBoundOfRight();
		int top=getBoundOfTop();
		int bottom=getBoundOfBottom();
		if(x<left)
		{
			//mEdgeEffectLeft.onAbsorb(left-x);
			x=left;
		}
		if(x>right)
			x=right;
		if(y<top)
		{
			mEdgeEffectTop.onAbsorb(top-y);
			y=top;
		}
		if(y>bottom)
		{
			mEdgeEffectBottom.onAbsorb(y-bottom);
			y=bottom;
		}
		awakenScrollBars();
		super.scrollTo(x, y);
	}
	
	private int getBitOfNum(int num)
	{
		if(num<10)
			return 1;
		if(num<100)
			return 2;
		if(num<1000)
			return 3;
		if(num<10000)
			return 4;
		if(num<100000)
			return 5;
		if(num<1000000)
			return 6;
		if(num<10000000)
			return 7;
		if(num<100000000)
			return 8;
		return 0;
	}

    public int getLineCount() {
        return mLayout != null ? mLayout.getLineCount() : 0;
    }

    public boolean isSelection(){
    	return getSelectionStart()!=getSelectionEnd();
    }

    public int getSelectionStart(){
    	return Selection.getSelectionStart(mBaseInputConnection.getEditable());
    }
    
    public int getSelectionEnd(){
    	return Selection.getSelectionEnd(mBaseInputConnection.getEditable());
    }
    
    public int getCursor(){
    	return getSelectionEnd();
    }
    
    public void bringPosToVisible(int pos){
    	if(mLayout!=null){
    		if(pos>=0 && pos<=getText().length()){
    			float x=mLayout.getPrimaryHorizontal(pos);
    			int line=mLayout.getLineForOffset(pos);
    			mLayout.getLineBounds(line, mBoundsOfCursor); 
    			int scrollX=getScrollX();
    			int scrollY=getScrollY();
    			if(mBoundsOfCursor.top<scrollY){
    				scrollY=mBoundsOfCursor.top;
    			}
    			if(mBoundsOfCursor.bottom>scrollY+getHeight())
    				scrollY=mBoundsOfCursor.bottom-getHeight();
    			
    			if(x<scrollX+mTextPaint.getTextSize())
    				scrollX= (int)( x-mTextPaint.getTextSize());
    			
    			if(x>scrollX+getWidth()-mTextPaint.getTextSize())
    				scrollX=(int) (x-getWidth()+mTextPaint.getTextSize());
    			
    			scrollTo(scrollX, scrollY);
    			postInvalidate();
    		}
    	}
    }
    
    public boolean setCursor(int cursor){
    	return setSelection(cursor, cursor);
    }
    
	public void showSoftKeyboard(){
		setFocusableInTouchMode(true);
		requestFocus();
		InputMethodManager inputMethodManager=(InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
		inputMethodManager.showSoftInput(this,InputMethodManager.SHOW_FORCED);
	}
	
	private int mDownState=0;
	private boolean isMoveSelectionStart(){
		return mDownState==1;
	}
	
	private boolean isMoveSelectionEnd(){
		return mDownState==2;
	}
	
	private boolean isMoveSelection(){
		return mDownState!=0;
	}
	
	@Override
	public boolean onDown(MotionEvent e) {
		mDownState=0;
		if(isSelection())
		{	
			int cursor=getCursor();
			float x=mLayout.getPrimaryHorizontal(cursor);
			int line=mLayout.getLineForOffset(cursor);
			mLayout.getLineBounds(line, mBoundsOfCursor); 
			int r=mBoundsOfCursor.height()/2;
			int y=mBoundsOfCursor.bottom + r;
			if( Math.sqrt( Math.pow(getScrollX()+e.getX()-x, 2f) + Math.pow(getScrollY()+e.getY()-y, 2f)  ) <= r){
				mDownState=2;
			}

			cursor=getSelectionStart();
			x=mLayout.getPrimaryHorizontal(cursor);
			line=mLayout.getLineForOffset(cursor);
			mLayout.getLineBounds(line, mBoundsOfCursor); 
			r=mBoundsOfCursor.height()/2;
			y=mBoundsOfCursor.bottom + r;
			if( Math.sqrt( Math.pow(getScrollX()+e.getX()-x, 2f) + Math.pow(getScrollY()+e.getY()-y, 2f)  ) <= r){
				mDownState=1;
			}
		}
		return true;
	}

	@Override
	public void onShowPress(MotionEvent e) {
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		Log.i(TAG, "onSingleTapUp");
		if(mLayout!=null){
			int line=mLayout.getLineForVertical(getScrollY()+(int) e.getY());
			int offset=mLayout.getOffsetForHorizontal(line, getScrollX()+(int)e.getX());
			setCursor(offset);
		}
		showSoftKeyboard();
		return false;
	}
	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		if(!isMoveSelection())
		{
			scrollBy((int)distanceX, (int )distanceY);
			postInvalidate();  
		}
		else{
			int line=mLayout.getLineForVertical(getScrollY()+(int) e2.getY()-(int)(1.5f*mLayout.getPaint().getTextSize()) );
			int offset=mLayout.getOffsetForHorizontal(line, getScrollX()+(int)e2.getX());
			int start=getSelectionStart();
			int end=getSelectionEnd();
			if(isMoveSelectionEnd()){
				if(offset<=start)
					offset=start+1;
				if(offset<=getText().length())
				{
					setSelection(start, offset);
					postInvalidate();
				}
			}else
			if(isMoveSelectionStart()){
				if(offset>=end)
					offset=end-1;
				if(offset>=0){
					setSelection(offset, end);
					postInvalidate();
				}
			}
		}
		return true;
	}

	@Override
	public void onLongPress(MotionEvent e) {
		Log.i(TAG, "onLongPress");
		if(mLayout!=null){
			int line=mLayout.getLineForVertical(getScrollY()+(int) e.getY());
			int offset=mLayout.getOffsetForHorizontal(line, getScrollX()+(int)e.getX());
			int start=offset-1;
			if(start<0)
				start=0;
			setSelection(start, offset);
		}
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {
		if(!isMoveSelection())
		{
			Log.i(TAG, "onFling");
			mScroller.fling(getScrollX(), getScrollY(), -(int)velocityX , -(int)velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE,  Integer.MAX_VALUE);
		}
		return true;
	}
	
    @Override  
    public void computeScroll() {  
    	//先判断mScroller滚动是否完成  
    	if (mScroller.computeScrollOffset()) 
    	{
    		//这里调用View的scrollTo()完成实际的滚动  
    		scrollTo(mScroller.getCurrX(), mScroller.getCurrY());  
    		//必须调用该方法，否则不一定能看到滚动效果  
    		postInvalidate();  
    	}  
    }
    
	public boolean setSelection(int start, int end) {
		Log.i(TAG, "setSelection:"+start+" "+end);
    	return mBaseInputConnection.setSelection(start, end);
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch(event.getKeyCode()){
		case KeyEvent.KEYCODE_SHIFT_LEFT:
			mDownState=1;
			break;
		case KeyEvent.KEYCODE_SHIFT_RIGHT:
			mDownState=2;
			break;
		default:
			return false;	
		}
		return true;
	}
	
	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		Log.i(TAG, "onKeyUp:"+event);
		Editable editable=getText();
		int start=Selection.getSelectionStart(editable);
		int end=Selection.getSelectionEnd(editable);
		if(event.getAction()==KeyEvent.ACTION_UP)
		switch(event.getKeyCode()){
		case KeyEvent.KEYCODE_DEL:
			if(start>=end)
				start=end-1;
			if(start>=0)
			editable.delete(start, end);
			break;
		case KeyEvent.KEYCODE_ENTER:
			editable.replace(start, end, "\n");
			setSelection(start+1, start+1);
			break;
		case KeyEvent.KEYCODE_DPAD_LEFT:
			if(isMoveSelectionStart()){
				start--;
				if(start>=0)
					setSelection(start, end);
			}else if(isMoveSelectionEnd()){
				end--;
				if(end>start)
					setSelection(start, end);
			}else {
				end--;
				if(end>=0)
					setSelection(end, end);
			}
			break;
		case KeyEvent.KEYCODE_DPAD_RIGHT:
			if(isMoveSelectionStart()){
				start++;
				if(start<end)
					setSelection(start, end);
			}else if(isMoveSelectionEnd()){
				end++;
				if(end<=editable.length())
					setSelection(start, end);
			}else {
				end++;
				if(end<=editable.length())
					setSelection(end, end);
			}
			break;
		case KeyEvent.KEYCODE_DPAD_UP :
			if(isMoveSelectionStart()){
				int line=mLayout.getLineForOffset(start);
				float x=mLayout.getPrimaryHorizontal(start);
				if(line>0)
				{
					int position=mLayout.getOffsetForHorizontal(line-1, x);
					if(position>=0 && position < end)
						setSelection(position, end);
				}
			}
			else
			{
				int line=mLayout.getLineForOffset(end);
				if(line>0){
					float x=mLayout.getPrimaryHorizontal(end);
					int position=mLayout.getOffsetForHorizontal(line-1, x);
					if(isMoveSelectionEnd()){
						if(position>start && position<=editable.length())
							setSelection(start, position);
					}
					else{
						setCursor(position);
					}
				}
			}
			break;
		case KeyEvent.KEYCODE_DPAD_DOWN:
			if(isMoveSelectionStart()){
				int line=mLayout.getLineForOffset(start);
				if(line<mLayout.getLineCount()-1){
					float x=mLayout.getPrimaryHorizontal(start);
					int position=mLayout.getOffsetForHorizontal(line+1, x);
					if(position>=0 && position < end)
						setSelection(position, end);
				}
			}else{
				int line=mLayout.getLineForOffset(end);
				if(line<mLayout.getLineCount()-1){
					float x=mLayout.getPrimaryHorizontal(end);
					int position=mLayout.getOffsetForHorizontal(line+1, x);
					if(isMoveSelectionEnd()){
						if(position>start && position<=editable.length())
							setSelection(start, position);
					}
					else
						setCursor(position);
				}
			}
			break;
		default:
			return false;	
		}
		return true;
	}

	public boolean performContextMenuAction(int id) {
		Log.i(TAG, "performContextMenuAction:"+id);
		Editable editable=getText();
		int start=Selection.getSelectionStart(editable);
		int end=Selection.getSelectionEnd(editable);
		switch (id) {
		case android.R.id.selectAll:
			setSelection(0, editable.length());
			break;
		case android.R.id.cut:
			try {
				ClipboardManager clipboardManager= (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
				clipboardManager.setText(editable.subSequence(start, end));
				editable.delete(start, end);
				setSelection(start, start);
			} catch (Exception e) {
				e.printStackTrace();
			}
			break;
		case android.R.id.copy:
			try {
				ClipboardManager clipboardManager= (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
				clipboardManager.setText(editable.subSequence(start, end));
				setSelection(end, end);
			} catch (Exception e) {
				e.printStackTrace();
			}
			break;
		case android.R.id.paste:
			try {
				ClipboardManager clipboardManager= (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
				CharSequence charSequence=clipboardManager.getText();
				editable.replace(start, end, charSequence);
				int t=start+charSequence.length();
				setSelection(t,t);
			} catch (Exception e) {
				e.printStackTrace();
			}
			break;
		default:
			return false;
		}
		return true;
	}


	@Override
	public void beforeTextChanged(CharSequence s, int start, int count,int after) {
	}


	@Override
	public void onTextChanged(CharSequence s, int start, int before, int count) {
	}


	@Override
	public void afterTextChanged(Editable s) {
		Log.i(TAG, "afterTextChanged");
		post(new Runnable() {
			@Override
			public void run() {
				bringPosToVisible(getCursor());
				postInvalidate();
			}
		});
	}
	
}
